深究推荐 @Autowired 对构造函数注解的原因

最近在开发的时候,使用 @Autowired 注解 Field,发现 IDE 报了一个警告,如下:

1
Spring Team recommends "Always use constructor based dependency injection in your beans. Always use assertions for mandatory dependencies".

翻译后的大概意思就是:
Spring 团队建议:总是在您的 bean 中使用构造函数建立依赖注入。总是使用断言强制依赖。

原来的写法是:

1
2
3
4
5
6
7
8
9
10
11
12
13
@Controller
public class UserController {
@Autowired
private UserService userService;

@RequestMapping(value = "/get")
public @ResponseBody getUser()
...
}
```

这样写就会出现上边那个警告。
按照 Spring 团队建议的写法是:

public class A {
/**

 *    注意多添加了一个 final 修饰
 */
private final B b;

@Autowired
public A(B b) {
    this.b = b;
}
...

}

1
2
3
4
5
6
7
8
9
10
@Autowired 明明可以对 Constructor,Fileld, Setter Methods or config Methods 进行注释。
那么为什么这里有这样的提示?对 Field 和 对 Constructor 进行注释有什么区别呢?

为了解答以上疑惑,还得结合 JVM 中对 Java 变量的初始化顺序进行分析:
**Java变量的初始化顺序为:**
静态变量或静态语句块 –> 实例变量或初始化语句块 –> 构造方法 –> @Autowired

所以,若有如下代码:

B.java 文件

@Getter
@Setter
@Service
public class B {

private String name;

private int age;

public User(){}

public User(String name, int age) {
    this.name = name;
    this.age = age;
}

@Override
public String toString() {
    return "Name=" + name + ", Age=" + age;
 }

}

1
2

A.java 文件

public class A {
private String name;

@Autowired
private B b;

public A() {
    this.name = b.getName();    
}
...

}
```

能正常完成编译,但是运行时会抛出 NPE。

被 @Autowired 注解的 Field 的底层注入流程可以理解为在配置文件中配置 bean,然后使用 setter 注入。
而被 @Autowired 注解的 Constructor 的底层注入流程就相当于是使用构造函数进行依赖注入了。